#include "Board.h"

vector<threatData*> Board::vThreatData;
Board::Board()
{
}


Board::~Board()
{
	for (size_t i = 0; i < size_; i++)
	{
		delete[] board_[i];
	}
	delete board_;
}
void Board::setSize(unsigned int size){
	this->size_ = size;
	board_ = new char*[size];
	for (size_t i = 0; i < size; i++)
	{
		board_[i] = (char*)calloc(size,sizeof(char));
		memset(board_[i], BLANK_TYPE, size);
	}
}
void Board::setValue(unsigned int r, unsigned int c, char v){
	if (inBoard(r, c)){
		board_[r][c] = v;
		if (win(r, c, v)){
			cout << "-----------------------------------------" << endl;
			cout << v << " win!"<<endl;
			cout << "-----------------------------------------" << endl;
		}
	}

}
bool Board::inBoard(unsigned int row, unsigned int collumn){
	if (row < 0 || row >= size_)
		return false;
	if (collumn < 0 || collumn >= size_)
		return false;
	return true;
}
char Board::getValue(unsigned int row, unsigned int collumn){
	if (inBoard(row, collumn))
		return board_[row][collumn];
	else
		return BLOCK_TYPE;
}
char Board::getValue(unsigned int row, unsigned int collumn, DIRECTION direct,int offset){
	Vec2 newPosition=getPosition(row, collumn, direct, offset);
	return getValue(newPosition.getRow(),  newPosition.getCollumn());
}


Vec2 Board::getNextMove(){
	return Vec2();
}
ostream& operator<<(ostream& os, Board& board){
	os << "+Begin Board"<<endl;
	os << setw(2)<<"";
	for (size_t i = 0; i < board.size_; i++)
	{
		os << setw(2) << i;
	}
	os << endl;
	for (size_t i = 0; i < board.size_; i++)
	{
		if (i > 9)
			os << i;
		else os << setw(2) << i;

		for (size_t j = 0; j < board.size_; j++)
		{
			os << setw(2) << board.getValue(i, j);
		}
		os<< endl;
	}
	os << "+End board"<<endl;
	return os;
}
Vec2 Board::getPosition(unsigned int row, unsigned int collumn, DIRECTION direction, int offset){
	int r = 0, c = 0;
	if (direction == HORIZONTAL){
		c = +offset;
	}
	else if (direction == VERTICAL)
		r = offset;
	else if (direction == DIAGONAL1){
		r = offset;
		c = offset;
	}
	else if (direction == DIAGONAL2){
		r = -offset;
		c = offset;
	}
	return Vec2(row + r, collumn + c);
}
char Board::getValue(Vec2 v){
	return getValue(v.getRow(), v.getCollumn());
}
char* Board::getLine(unsigned int row, unsigned int collumn,DIRECTION direction){
	char* result = nullptr;
	char* s = new char[BUFFER_LENGTH];
	s[1] = '\0';
	s[0]=getValue(row, collumn, direction, 0);
	char* t = new char[BUFFER_LENGTH];
	t[1] = '\0';
	for (size_t i = 0; i < WIDTH_LIMIT; i++)
	{
		t[0]=getValue(row, collumn, direction,i+1);
		s = strcat(s, t);
	}
	delete t;
	
	for (size_t i = 0; i < WIDTH_LIMIT; i++)
	{
		
		t = new char[BUFFER_LENGTH];
		t[0] = getValue(row, collumn, direction, -1-i);
		t[1] = '\0';

		strcat(t,s);
		free(s);
		s = t;
	}
	return t;
	
}

void Board::initThreatData(){
	//openTwo1
	int aiOpenTwo1[] = {1,2};
	vector<int> vOpenTwo1(aiOpenTwo1, aiOpenTwo1+ sizeof(aiOpenTwo1) / sizeof(int));
	vThreatData.push_back(new threatData("OpenTwo1", "---xx-", vOpenTwo1));
	//openTwo2
	int aiOpenTwo2[] = { 3, 4 };
	vector<int> vOpenTwo2(aiOpenTwo2, aiOpenTwo2 + sizeof(aiOpenTwo2) / sizeof(int));
	vThreatData.push_back(new threatData("OpenTwo2", "-xx---", vOpenTwo2));
	//openThree
	int aiOpenThree[] = { 0, 4 };
	vector<int> vOpenThree(aiOpenThree,aiOpenThree+sizeof(aiOpenThree)/sizeof(int));
	Board::vThreatData.push_back(new threatData("OpenThree","-xxx-", vOpenThree));
	//brokenThree1
	int aiBrokenThree1[] = {2};
	vector<int> vBrokenThree1(aiBrokenThree1, aiBrokenThree1+ sizeof(aiBrokenThree1) / sizeof(int));
	vThreatData.push_back(new threatData("BrokenThree", "-x-xx-", vBrokenThree1));
	//brokenThree2
	int aiBrokenThree2[] = { 3 };
	vector<int> vBrokenThree2(aiBrokenThree2, aiBrokenThree2 + sizeof(aiBrokenThree2) / sizeof(int));
	vThreatData.push_back(new threatData("BrokenThree", "-xx-x-", vBrokenThree2));
	//openFour
	int aiOpenFour[] = { 0, 5 };
	vector<int> vOpenFour(aiOpenFour,aiOpenFour+sizeof(aiOpenFour)/sizeof(int));
	vThreatData.push_back(new threatData("OpenFour","-xxxx-", vOpenFour));
	//blockFour1
	vector<int> vBlockFour1;
	vBlockFour1.push_back(5);
	vThreatData.push_back(new threatData("BlockFour1","oxxxx-", vBlockFour1));
	//blockFour2
	vector<int> vBlockFour2;
	vBlockFour2.push_back(0);
	vThreatData.push_back(new threatData("BlockFour2","-xxxxo", vBlockFour2));
	//five
	vector<int> vFive;
	vThreatData.push_back(new threatData("Five","xxxxx", vFive));

}
void Board::clearThreatData(){
	for each (threatData* e in Board::vThreatData)
	{
		delete e;
	}
}
bool Board:: win(unsigned int  row, unsigned int collumn, char type){
	for (size_t i = 0; i < DIRECTION_COUNT; i++)
	{
		if (this->findGain(row, collumn,type, (DIRECTION)i, vector<Vec2>()) == FIVE)
			return true;
	}
	return false;
}
int Board::findGain(unsigned int row, unsigned int collumn,char type,DIRECTION direction, vector<Vec2>&gain){

	for each (threatData* thD in Board::vThreatData)
	{
		char* line = getLine(row, collumn, direction);
		char* strCmp = strstr(line, thD->getThreatType());
		if (strCmp != nullptr){
			if (strcmp(thD->getThreatName(), "Five") == 0){
				delete[] line;
				return FIVE;
			}
			int offset = strCmp - line;
			Vec2 head = getPosition(row, collumn, direction, -WIDTH_LIMIT);

			Vec2 startThreat= head.add(getPosition(0, 0, direction, offset));
			
			for each (int offset in thD->getGainOffset())
			{
				Vec2 gainOffset = getPosition(0, 0, direction, offset);
				Vec2 matchOffset = startThreat.add(gainOffset);
				gain.push_back(matchOffset);
			}
		}

		delete line;

	}
	return NON_FIVE;

}
char Board::getOppositeType(char type){
	if (type == OUR_TYPE)
		return ENEMY_TYPE;
	else if (type == ENEMY_TYPE)
		return OUR_TYPE;
}
void Board::setBlank(vector<Vec2> v){
	for each (Vec2 vec in v)
	{
		setValue(vec.getRow(), vec.getCollumn(), BLANK_TYPE);
	}
}
int Board::threatSearch(unsigned int row, unsigned int collumn, char type,vector<Vec2>&traceGain){
	for (int direction = 0; direction < 4; direction++)
	{
		vector<Vec2>vGain;
		if (row == 8 && collumn == 7 && direction == 3){
			cout << *this << endl;
		}
		if (findGain(row, collumn, type, (DIRECTION)direction, vGain) == FIVE){
			//cout << *this << endl;
			return FIVE;
		}
		else{
			
			for each (Vec2 gain in vGain)
			{
				for each (Vec2 gain in vGain)
				{
					setValue(gain.getRow(), gain.getCollumn(), getOppositeType(type));
				}
				setValue(gain.getRow(), gain.getCollumn(), type);
				traceGain.push_back(Vec2(gain.getRow(), gain.getCollumn()));
				//cout << *this << endl;
				if (threatSearch(gain.getRow(), gain.getCollumn(), type,traceGain) == FIVE){
					
					return FIVE;
				}
				else{
					for each (Vec2 gain in vGain)
					{
						setValue(gain.getRow(), gain.getCollumn(), BLANK_TYPE);
					}
					
				}
				traceGain.pop_back();
			}
		}
	}
	return NON_FIVE;
}